// StopwatchExample2.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "hwindatetime.h"
#include "hwinvariant.h"
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>  
#include <algorithm> 
#include <vector> 


using namespace harlinn::windows;
using namespace std;

/*
template<typename T>
class Buffer
{ 
    size_t length; 
    T* ptr;
public:
    Buffer(); 
    Buffer(const Buffer& other); 
    Buffer(const Buffer& first,const Buffer& second);
    Buffer( size_t theLength, const T& theValue);
    ~Buffer(); 
    int compare(const Buffer& other) const;
    bool operator < ( const Buffer& other );
    bool operator > ( const Buffer& other );
    Buffer& operator = ( const Buffer& other ); 
    inline friend Buffer operator + (const Buffer& first,const Buffer& second);
};


template<typename T>
class Buffer2
{ 
    size_t length; 
    T* ptr;
public:
    Buffer2(); 
    Buffer2(const Buffer2& other); 
    Buffer2(Buffer2&& other); 
    Buffer2(const Buffer2& first,const Buffer2& second);
    Buffer2( size_t theLength, const T& theValue); 
    ~Buffer2(); 
    int compare(const Buffer2& other) const;
    bool operator < ( const Buffer2& other );
    bool operator > ( const Buffer2& other );
    Buffer2& operator = ( const Buffer2& other ); 
    Buffer2& operator = ( Buffer2&& other ); 
    inline friend Buffer2 operator + (const Buffer2& first,const Buffer2& second);
};
 */

//////////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
class Buffer
{ 
    size_t length; 
    T* ptr;
public:
    Buffer() 
        : length(0),
          ptr(0) 
    {}

    Buffer(const Buffer& other) 
        : length(other.length),
          ptr(0) 
    {
        if(length)
        {
            ptr = new T[length]; 
            copy(other.ptr,other.ptr+length,ptr);
        }
    }

    Buffer(const Buffer& first,const Buffer& second)
        : length(first.length,second.length),
          ptr(0) 
    {
        if(length)
        {
            ptr = new T[length]; 
            copy(first.ptr,first.ptr+first.length,ptr);
            copy(second.ptr,second.ptr+second.length,ptr+first.length);
        }
    }


    Buffer( size_t theLength, const T& theValue) 
        : length(theLength),
          ptr(0) 
    {
        if(theLength)
        {
            ptr = new T[length];
            fill(ptr,ptr+length,theValue);
        }
    }

    ~Buffer() 
    {
        delete ptr;
    }

int compare(const Buffer& other) const
{
    int result = 0;
    size_t compareLength = min(length,other.length);
    for(size_t i = 0; i < compareLength; i++)
    {
        const T& v1 = ptr[i];
        const T& v2 = other.ptr[i];
        if(v1 > v2)
        {
            result = 1;
            break;
        }
        if(v1 < v2)
        {
            result = -1;
            break;
        }
    }
    if(result == 0)
    {
        if(length > other.length)
        {
            result = 1;
        }
        else if(length < other.length)
        {
            result = -1;
        }
    }
    return result;
    //return ptr[0] - other.ptr[0];
}

    bool operator < ( const Buffer& other )
    {
        return compare(other) < 0;
    }

    bool operator > ( const Buffer& other )
    {
        return compare(other) > 0;
    }


    Buffer& operator = ( const Buffer& other ) 
    { 
        if(other.ptr != ptr)
        {
            delete ptr;
            length = other.length;
            ptr = new T[length]; 
            copy(other.ptr,other.ptr+length,ptr);
        }
        return *this;
    }

    inline friend Buffer operator + (const Buffer& first,const Buffer& second)
    {
        return Buffer(first,second);
    }

};


template<typename T>
class Buffer2
{ 
    size_t length; 
    T* ptr;
public:
    Buffer2() 
        : length(0),
          ptr(0) 
    {}

    Buffer2(const Buffer2& other) 
        : length(other.length),
          ptr(0) 
    {
        if(length)
        {
            ptr = new T[length]; 
            copy(other.ptr,other.ptr+length,ptr);
        }
    }

    Buffer2(Buffer2&& other) 
        : length(other.length),
          ptr(0) 
    {
        if(length)
        {
            ptr = other.ptr; 
            other.ptr = nullptr;
            other.length = 0;
        }
    }


    Buffer2(const Buffer2& first,const Buffer2& second)
        : length(first.length,second.length),
          ptr(0) 
    {
        if(length)
        {
            ptr = new T[length]; 
            copy(first.ptr,first.ptr+first.length,ptr);
            copy(second.ptr,second.ptr+second.length,ptr+first.length);
        }
    }


    Buffer2( size_t theLength, const T& theValue) 
        : length(theLength),
          ptr(0) 
    {
        if(theLength)
        {
            ptr = new T[length];
            fill(ptr,ptr+length,theValue);
        }
    }

    ~Buffer2() 
    {
        delete ptr;
    }

    int compare(const Buffer2& other) const
    {
        
        int result = 0;
        size_t compareLength = min(length,other.length);
        for(size_t i = 0; i < compareLength; i++)
        {
            const T& v1 = ptr[i];
            const T& v2 = other.ptr[i];
            if(v1 > v2)
            {
                result = 1;
                break;
            }
            if(v1 < v2)
            {
                result = -1;
                break;
            }
        }
        if(result == 0)
        {
            if(length > other.length)
            {
                result = 1;
            }
            else if(length < other.length)
            {
                result = -1;
            }
        }
        return result;
        
        //return ptr[0] - other.ptr[0];
    }

    bool operator < ( const Buffer2& other )
    {
        return compare(other) < 0;
    }

    bool operator > ( const Buffer2& other )
    {
        return compare(other) > 0;
    }


    Buffer2& operator = ( const Buffer2& other ) 
    { 
        if(other.ptr != ptr)
        {
            delete ptr;
            length = other.length;
            ptr = new T[length]; 
            copy(other.ptr,other.ptr+length,ptr);
        }
        return *this;
    }

    Buffer2& operator = ( Buffer2&& other ) 
    { 
        if(this != &other)
        {
            delete ptr;
            length = other.length;
            ptr = other.ptr; 
            other.ptr = nullptr;
            other.length = 0;
        }
        return *this;
    }

    inline friend Buffer2 operator + (const Buffer2& first,const Buffer2& second)
    {
        return Buffer2(first,second);
    }

};

void BufferTestPushBack(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    Stopwatch stopwatch;
    vector< buffer_t > buffers;	
    buffers.reserve(bufferCount);

    printf("Test vector push_back: copy constructible/copy assignable\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        buffers.push_back(buffer_t(size_t(bufferSize),c));
    }

    stopwatch.Stop();
    printf("\tpush_back of %d elements in %f ms\n",bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(buffers.begin(),buffers.end());
    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}


void BufferTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    Stopwatch stopwatch;
    vector< buffer_t > destinationBuffers(bufferCount);
    vector< buffer_t > sourceBuffers;
    sourceBuffers.reserve(bufferCount);

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers.push_back(buffer_t(size_t(bufferSize),c));
    }

    printf("Test vector copy: copy constructible/copy assignable\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d elements in %f ms\n",bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(destinationBuffers.begin(),destinationBuffers.end());
    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}


void Buffer2TestPushBack(int bufferCount, size_t bufferSize) 
{
    typedef Buffer2 <char> buffer_t;
    Stopwatch stopwatch;
    vector< buffer_t > buffers;	
    buffers.reserve(bufferCount);

    printf("Test vector push_back: move constructible/move assignable\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        buffers.push_back(buffer_t(size_t(bufferSize),c));
    }

    stopwatch.Stop();
    printf("\tpush_back of %d elements in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(buffers.begin(),buffers.end());
    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}

void Buffer2Test(int bufferCount, size_t bufferSize) 
{
    typedef Buffer2 <char> buffer_t;
    Stopwatch stopwatch;
    vector< buffer_t > destinationBuffers(bufferCount);	
    vector< buffer_t > sourceBuffers;
    sourceBuffers.reserve(bufferCount);

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers.push_back(buffer_t(size_t(bufferSize),c));
    }

    printf("Test vector move constructible/move assignable\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d elements in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(destinationBuffers.begin(),destinationBuffers.end());
    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}


void BufferPointerTestPushBack(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    vector<buffer_t*> buffers;
    buffers.reserve(bufferCount);

    Stopwatch stopwatch;
    printf("Test vector of raw pointers\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        buffers.push_back(new buffer_t(size_t(bufferSize),c));
    }
    stopwatch.Stop();
    printf("\tpush_back of %d pointers in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(buffers.begin(),buffers.end(), [] (buffer_t* a, buffer_t* b) 
    { 
        if(a && b)
        {
            return a->compare(*b) < 0;
        }
        if(b)
        {
            return true;
        }
        return false; 
    });

    stopwatch.Stop();
    printf("\tsorted %d pointers in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    for(auto it = buffers.begin(); it != buffers.end(); it++) 
    {  
        buffer_t* ptr = *it;
        delete ptr;
    }
}

void BufferPointerTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    vector<buffer_t*> destinationBuffers(bufferCount);	
    vector<buffer_t*> sourceBuffers;
    sourceBuffers.reserve(bufferCount);

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers.push_back(new buffer_t(size_t(bufferSize),c));
    }


    Stopwatch stopwatch;
    printf("Test vector of raw pointers \n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d pointers in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(destinationBuffers.begin(),destinationBuffers.end(), [] (buffer_t* a, buffer_t* b) 
    { 
        if(a && b)
        {
            return a->compare(*b) < 0;
        }
        if(b)
        {
            return true;
        }
        return false; 
    });

    stopwatch.Stop();
    printf("\tsorted %d pointers in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    for(auto it = destinationBuffers.begin(); it != destinationBuffers.end(); it++) 
    {  
        buffer_t* ptr = *it;
        delete ptr;
    }
}


void BufferArrayOfPointerTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    buffer_t** destinationBuffers = new buffer_t*[bufferCount];
    buffer_t** sourceBuffers = new buffer_t*[bufferCount];

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers[i] = new buffer_t(size_t(bufferSize),c);
    }


    Stopwatch stopwatch;
    printf("Test array of raw pointers\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d pointers in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    buffer_t** first = destinationBuffers;
    buffer_t** last = &destinationBuffers[size_t(bufferCount)];
    sort(first,last, [] (buffer_t* a, buffer_t* b) 
    { 
        if(a && b)
        {
            return a->compare(*b) < 0;
        }
        if(b)
        {
            return true;
        }
        return false; 
    });

    stopwatch.Stop();
    printf("\tsorted %d pointers in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    for(int i = 0; i < bufferCount; i++) 
    {  
        delete destinationBuffers[i];
    }
    delete destinationBuffers;
    delete sourceBuffers;
}

void BufferArrayTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    buffer_t* destinationBuffers = new buffer_t[bufferCount];
    buffer_t* sourceBuffers = new buffer_t[bufferCount];

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers[i] = buffer_t(size_t(bufferSize),c);
    }


    Stopwatch stopwatch;
    printf("Test array: copy constructible/copy assignable\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d elements in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    buffer_t* first = destinationBuffers;
    buffer_t* last = &destinationBuffers[size_t(bufferCount)];
    sort(first,last, [] (const buffer_t& a, const buffer_t& b) 
    { 
        return a.compare(b) < 0;
    });

    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    delete[] destinationBuffers;
    delete[] sourceBuffers;
}


void BufferArrayNoLambdaTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    buffer_t* destinationBuffers = new buffer_t[bufferCount];
    buffer_t* sourceBuffers = new buffer_t[bufferCount];

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers[i] = buffer_t(size_t(bufferSize),c);
    }


    Stopwatch stopwatch;
    printf("Test array: Copy constructible/copy assignable (no lambda)\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d elements in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    buffer_t* first = destinationBuffers;
    buffer_t* last = &destinationBuffers[size_t(bufferCount)];
    sort(first,last);

    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    delete[] destinationBuffers;
    delete[] sourceBuffers;
}


void Buffer2ArrayNoLambdaTest(int bufferCount, size_t bufferSize) 
{
    typedef Buffer2 <char> buffer_t;
    buffer_t* destinationBuffers = new buffer_t[bufferCount];
    buffer_t* sourceBuffers = new buffer_t[bufferCount];

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers[i] = buffer_t(size_t(bufferSize),c);
    }


    Stopwatch stopwatch;
    printf("Test array: Copy of move constructible/move assignable (no lambda)\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d elements in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    buffer_t* first = destinationBuffers;
    buffer_t* last = &destinationBuffers[size_t(bufferCount)];
    sort(first,last);

    stopwatch.Stop();
    printf("\tsorted %d elements in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    delete[] destinationBuffers;
    delete[] sourceBuffers;
}


void Buffer_shared_ptr_TestPushBack(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    vector< shared_ptr<buffer_t> > buffers;	
    buffers.reserve(bufferCount);

    Stopwatch stopwatch;
    printf("Test vector: push_back of shared_ptrs'\n");
    stopwatch.Start();

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        buffers.push_back(make_shared<buffer_t>(size_t(bufferSize),c));
    }
    stopwatch.Stop();
    printf("\tpush_back of %d shared_ptrs' in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(buffers.begin(),buffers.end(), [] (const shared_ptr<buffer_t>& a, const shared_ptr<buffer_t>& b) 
    { 
        if(a && b)
        {
            return a->compare(*b.get()) < 0;
        }
        if(b)
        {
            return true;
        }
        return false;
    });

    stopwatch.Stop();
    printf("\tsorted %d shared_ptrs' in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}


void Buffer_shared_ptr_Test(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    vector< shared_ptr<buffer_t> > destinationBuffers(bufferCount);	
    vector< shared_ptr<buffer_t> > sourceBuffers;
    sourceBuffers.reserve(bufferCount);

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers.push_back(make_shared<buffer_t>(size_t(bufferSize),c));
    }

    Stopwatch stopwatch;
    printf("Test vector: Copy of shared_ptrs'\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopied %d shared_ptrs' in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();
    sort(destinationBuffers.begin(),destinationBuffers.end(), [] (const shared_ptr<buffer_t>& a, const shared_ptr<buffer_t>& b) 
    { 
        if(a && b)
        {
            return a->compare(*b.get()) < 0;
        }
        if(b)
        {
            return true;
        }
        return false;
    });

    stopwatch.Stop();
    printf("\tsorted %d shared_ptrs' in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
}

void BufferArrayOf_shared_ptr_Test(int bufferCount, size_t bufferSize) 
{
    typedef Buffer <char> buffer_t;
    shared_ptr<buffer_t>* destinationBuffers = new shared_ptr<buffer_t>[bufferCount];	
    shared_ptr<buffer_t>* sourceBuffers = new shared_ptr<buffer_t>[bufferCount];	

    for(int i = 0; i < bufferCount; i++) 
    {
        char c = i%24;
        sourceBuffers[i] = make_shared<buffer_t>(size_t(bufferSize),c);
    }


    Stopwatch stopwatch;
    printf("Test array: shared_ptrs'\n");
    stopwatch.Start();
    for(int i = 0; i < bufferCount; i++) 
    {
        destinationBuffers[i] = sourceBuffers[i];
    }
    stopwatch.Stop();
    printf("\tcopy of %d shared_ptrs' in %f ms\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );
    stopwatch.Restart();

    shared_ptr<buffer_t>* first = destinationBuffers;
    shared_ptr<buffer_t>* last = &destinationBuffers[size_t(bufferCount)];
    sort(first,last, [] (const shared_ptr<buffer_t>& a, const shared_ptr<buffer_t>& b) 
    { 
        if(a && b)
        {
            return a->compare(*b.get()) < 0;
        }
        if(b)
        {
            return true;
        }
        return false;
    });

    stopwatch.Stop();
    printf("\tsorted %d shared_ptrs' in %f ms\n\n", bufferCount ,stopwatch.Elapsed().TotalMilliseconds() );

    delete[] destinationBuffers;
    delete[] sourceBuffers;
}

int _tmain(int argc, _TCHAR* argv[])
{
    size_t bufferSize = 680*480*8;
    int bufferCount = 500;

    int variantSize = sizeof(Variant);
    int propVariantSize = sizeof(PropertyVariant);

    Variant v;
    PropertyVariant pv;

    printf("%d\n",variantSize);
    printf("%d\n",propVariantSize);

    BufferTestPushBack(bufferCount,bufferSize);
    BufferTest(bufferCount,bufferSize);

    Buffer2TestPushBack(bufferCount,bufferSize);
    Buffer2Test(bufferCount,bufferSize);

    BufferPointerTestPushBack(bufferCount,bufferSize);
    BufferPointerTest(bufferCount,bufferSize);

    Buffer_shared_ptr_TestPushBack(bufferCount,bufferSize);
    Buffer_shared_ptr_Test(bufferCount,bufferSize);

    BufferArrayOfPointerTest(bufferCount,bufferSize);
    BufferArrayTest(bufferCount,bufferSize);
    BufferArrayNoLambdaTest(bufferCount,bufferSize);
    Buffer2ArrayNoLambdaTest(bufferCount,bufferSize);
    BufferArrayOf_shared_ptr_Test(bufferCount,bufferSize);
	return 0;
}

